/* Include these
   #include <uuid/uuid.h>
   #include <stdint.h>
   #include <nit/list.h>
   #include <nit/hset.h>
   #include <nit/hmap.h>
*/

typedef struct Uii_expr Uii_expr;
typedef struct Uii_elist Uii_elist;
typedef struct Uii_cnti Uii_cnti;
typedef struct Uii_u Uii_u;
typedef void (Uii_bf)(Uii_cnti *, Uii_u *); /* Binary function */
typedef struct Uii_f Uii_f;

enum uii_ftype { UII_E, UII_D, UII_C };
enum uii_etype { UII_END, UII_FA, UII_VAL, UII_VAR };

typedef uuid_t Uii_vid;
typedef uuid_t Uii_uid;

typedef struct {
	Uii_uid f_id;
	Uii_elist *args;
} Uii_fa;  /* function applied */

struct Uii_expr {
	enum uii_etype type;
	union {
		void *val;
		Uii_vid var;
		Uii_fa fa;
	} i;
};

struct Uii_elist {
	Nit_list list;
	Uii_expr *expr;
};

struct Uii_cnti {
	Uii_cnti *up;
	Nit_hmap *env;
	Uii_elist *ret;
	Uii_elist *args;
};

struct Uii_u {
	int dirfd;
	Nit_hmap *load;
	Nit_hentry *stack;
	void *focus;
}; /* universe, all unique values */

/* ef: Executable function, expected to be present in executable */
/* df: Dynamic function, expected to be loadable from shared object */

typedef struct {
	Uii_bf *bf;
        char *lib;
	char *sym;
} Uii_df;

struct Uii_f {
        Uii_uid id;
	enum uii_ftype type;
	int save;
	union {
		Uii_bf *e;
		Uii_df *d;
		Uii_elist *bod;
	} i; /* Implementation */
};

/* typedef struct { */
/* 	FILE *fp; */
/* 	char type; */
/* } UIIFILE; */

Uii_expr *
uii_expr_val(void *val);

Uii_expr *
uii_expr_var(Uii_vid var);

Uii_expr *
uii_expr_fa(Uii_uid f_id, Uii_elist *args);

Uii_elist *
uii_elist_new(Uii_expr *expr, Uii_elist *next);

Uii_elist *
uii_nest(Uii_expr *expr);

Uii_elist *
uii_elist_va(int cnt, ...);

Uii_cnti *
uii_cnti_new(Uii_cnti *up, Uii_elist *ret, Uii_elist *args);

Uii_cnti *
uii_cnti_expr(Uii_expr *expr);

Uii_u *
uii_u_new(const char *dir, void *focus);

int
uii_u_add(Uii_u *u, Uii_f *f);

int
uii_u_ser(Uii_u *u, Uii_f *f);

/* Uii_f * */
/* uii_u_load(Uii_u *u, Uii_uid id); */

Uii_f *
uii_u_get(Uii_u *u, Uii_uid id);

Uii_f *
uii_ef(Uii_uid id, Uii_bf bf);

int
uii_dopen(const char *lib);

void
uii_dclose(const char *lib);

Uii_f *
uii_hdf(Uii_uid id, void *handle, const char *lib, const char *sym, int save);

Uii_f *
uii_df(Uii_uid id, const char *lib, const char *sym, int save);

Uii_f *
uii_cf(Uii_uid id, Uii_elist *bod, int save);

void
uii_free(Uii_f *f);

int
uii_eval(Uii_cnti *cnti, Uii_u *u);
